#region Using statementes
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using RhythmComet.Physics;
using FMOD;
using RhythmComet.Services;
using RhythmComet.Particles;
#endregion

namespace RhythmComet.Gameplay
{
    public class Comet : DrawableGameComponent
    {
        #region Fields and properties
        RhythmCometGame game;
        
        Effect effect;
        Matrix viewMatrix;
        Matrix projectionMatrix;
        Matrix worldMatrix;
        VertexDeclaration vertexDeclaration;
        ParticleVertex[] vertice;

        Vector2 cometLocation;
        ParticleSystem cometParticleSys;
        InputHandler input;
        Texture2D texture;

        float verticalLimit = 200.0f;
        float horizontalLimit = 360.0f;

        BoundingSphere bound;

        private float timeBetweenCometSpray;
        private float timeTillCometSpray;

        public Color Color
        {
            get { return this.cometParticleSys.CurrentColor; }
        }

        public BoundingSphere Bound
        {
            get { return bound; }
        }

        public Vector2 Location
        {
            get { return cometLocation; }
        }
        #endregion

        #region Initializing
        public Comet(Game game): base(game)
        {
            this.game = (RhythmCometGame)game;

            ParticleSystemSettings settings = new ParticleSystemSettings();
            settings.textureFilename = @"sprites\cometSprite";

            settings.minInitialSpeed = 60;
            settings.maxInitialSpeed = 15;

            settings.minAcceleration = 0;
            settings.maxAcceleration = 0;

            settings.minLifetime = 1.0f;
            settings.maxLifetime = 1.0f;

            settings.minScale = 3.0f;
            settings.maxScale = 3.0f;

            settings.minNumParticles = 10;
            settings.maxNumParticles = 10;

            settings.minRotationSpeed = -(MathHelper.PiOver4 / 2.0f);
            settings.maxRotationSpeed = MathHelper.PiOver4 / 2.0f;

            cometParticleSys = new ParticleSystem(this.game, 2000, new DirectionalForce3D(200.0f, new Vector3(0.0f, -1.0f, 0.0f)), settings);
            cometParticleSys.CurrentColor = Color.Red;
            game.Components.Add(cometParticleSys);

            this.cometLocation = Vector2.Zero;
            this.input = this.game.Input;

            this.timeBetweenCometSpray = .001f;
            this.timeTillCometSpray = 0.0f;

            this.bound = new BoundingSphere(new Vector3(this.cometLocation, 0.0f), 5.0f);
        }

        public override void Initialize()
        {
            InitializeCamera();
            InitializeConstants();
            base.Initialize();
        }

        private void InitializeCamera()
        {
            this.projectionMatrix = game.Camera.Projection;
            this.viewMatrix = game.Camera.View;
            this.worldMatrix = Matrix.Identity;
        }

        private void InitializeConstants()
        {
            this.vertice = new ParticleVertex[1];
            vertice[0] = new ParticleVertex();
            vertexDeclaration = new VertexDeclaration(game.GraphicsDevice, ParticleVertex.VertexElements);
            game.GraphicsDevice.VertexDeclaration = vertexDeclaration;
            game.GraphicsDevice.RenderState.DepthBufferEnable = true;
            game.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;
        }

        protected override void LoadContent()
        {
            Effect tempEffect = game.Content.Load<Effect>(@"effects\particleEffect");
            effect = tempEffect.Clone(game.GraphicsDevice);

            this.texture = game.Content.Load<Texture2D>(@"sprites\cometSprite");
            base.LoadContent();
        }
        #endregion

        public void Reset()
        {
            cometLocation = Vector2.Zero;
            bound.Center.X = cometLocation.X;
            bound.Center.Y = cometLocation.Y;
            this.cometParticleSys.CurrentColor = Color.Red;
        }

        #region Update and Draw
        public override void Update(GameTime gameTime)
        {
            vertice[0].Position = new Vector3(this.cometLocation, 0);
            vertice[0].Color = this.cometParticleSys.CurrentColor;
            vertice[0].PointSize = 30;
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
            UpdateComet(dt);

            timeTillCometSpray -= dt;
            if (timeTillCometSpray < 0)
            {
                cometParticleSys.AddParticles(cometLocation);

                timeTillCometSpray = timeBetweenCometSpray;
            }

            base.Update(gameTime);
        }

        private void UpdateComet(float dt)
        {
            // gamepad analogico
            if (input.GamePadState.ThumbSticks.Left != Vector2.Zero)
                this.cometLocation += (input.GamePadState.ThumbSticks.Left * 5.0f);

            if (this.cometLocation.X > horizontalLimit)
                this.cometLocation.X = horizontalLimit;
            if (this.cometLocation.X < -horizontalLimit)
                this.cometLocation.X = -horizontalLimit;
            if (this.cometLocation.Y > verticalLimit)
                this.cometLocation.Y = verticalLimit;
            if (this.cometLocation.Y < -verticalLimit)
                this.cometLocation.Y = -verticalLimit;

            // gamepad digital
            if (input.GamePadState.DPad.Left == ButtonState.Pressed && this.cometLocation.X > -horizontalLimit)
                this.cometLocation.X -= 5.0f;
            if (input.GamePadState.DPad.Right == ButtonState.Pressed && this.cometLocation.X < horizontalLimit)
                this.cometLocation.X += 5.0f;
            if (input.GamePadState.DPad.Up == ButtonState.Pressed && this.cometLocation.Y < verticalLimit)
                this.cometLocation.Y += 5.0f;
            if (input.GamePadState.DPad.Down == ButtonState.Pressed && this.cometLocation.Y > -verticalLimit)
                this.cometLocation.Y -= 5.0f;

            if (input.GamePadState.Buttons.A == ButtonState.Pressed)
                this.cometParticleSys.CurrentColor = Color.Green;
            if (input.GamePadState.Buttons.B == ButtonState.Pressed)
                this.cometParticleSys.CurrentColor = Color.Red;
            if (input.GamePadState.Buttons.X == ButtonState.Pressed)
                this.cometParticleSys.CurrentColor = Color.Blue;
            if (input.GamePadState.Buttons.Y == ButtonState.Pressed)
                this.cometParticleSys.CurrentColor = Color.Yellow;

            // teclado
#if !XBOX
            if (input.KeyboardState.IsKeyDown(Keys.Left) && this.cometLocation.X > -horizontalLimit)
                this.cometLocation.X -= 5.0f;
            if (input.KeyboardState.IsKeyDown(Keys.Right) && this.cometLocation.X < horizontalLimit)
                this.cometLocation.X += 5.0f;
            if (input.KeyboardState.IsKeyDown(Keys.Up) && this.cometLocation.Y < verticalLimit)
                this.cometLocation.Y += 5.0f;
            if (input.KeyboardState.IsKeyDown(Keys.Down) && this.cometLocation.Y > -verticalLimit)
                this.cometLocation.Y -= 5.0f;

            if (input.WasPressed(Keys.A))
                this.cometParticleSys.CurrentColor = Color.Green;
            if (input.WasPressed(Keys.S))
                this.cometParticleSys.CurrentColor = Color.Red;
            if (input.WasPressed(Keys.D))
                this.cometParticleSys.CurrentColor = Color.Blue;
            if (input.WasPressed(Keys.F))
                this.cometParticleSys.CurrentColor = Color.Yellow;
#endif

            bound.Center.X = cometLocation.X;
            bound.Center.Y = cometLocation.Y;
        }

        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.VertexDeclaration = vertexDeclaration;

            effect.Parameters["World"].SetValue(worldMatrix);
            effect.Parameters["View"].SetValue(viewMatrix);
            effect.Parameters["Projection"].SetValue(projectionMatrix);
            effect.Parameters["ColorMap"].SetValue(texture);
            effect.CurrentTechnique = effect.Techniques[0];

            effect.Begin();
            effect.CurrentTechnique.Passes[0].Begin();
            game.GraphicsDevice.DrawUserPrimitives(PrimitiveType.PointList, vertice, 0, 1);
            effect.CurrentTechnique.Passes[0].End();
            effect.End(); 
            base.Draw(gameTime);
        }
        #endregion
    }
}